package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import sun.plugin.util.UIUtil;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author atguigu-mqx
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    //  使用redisson 做分布式锁！
    @Override
    public void testLock() {
        //  获取到锁
        RLock lock = redissonClient.getLock("lock");

        lock.lock();
        try {
            //  编写业务逻辑
            //  业务逻辑
            String numValue = redisTemplate.opsForValue().get("num");
            //  判断
            if (StringUtils.isEmpty(numValue)){
                return;
            }
            //  如果不是空，进行+1 操作！ 在写入缓存！
            int num = Integer.parseInt(numValue);

            //  写入缓存
            redisTemplate.opsForValue().set("num",String.valueOf(++num));
        } finally {
            //  解锁！
            lock.unlock();
        }
    }

    @Override
    public String readLock() {
        //  获取缓存的数据
        RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock");
        //  获取到读锁
        RLock rLock = rwLock.readLock();
        //  这个锁默认10秒钟解锁
        rLock.lock(10,TimeUnit.SECONDS);
        //  业务逻辑
        String msg = redisTemplate.opsForValue().get("message");
        //  解锁 暂时注释掉，我们想看10秒钟自动解锁的效果！
        //  rLock.unlock();
        //  返回读取到的数据
        return msg;
    }

    @Override
    public String writeLock() {
        //  写入缓存的数据
        RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock");
        //  获取写锁对象
        RLock rLock = rwLock.writeLock();

        //  上锁
        rLock.lock(10,TimeUnit.SECONDS);

        //  写入数据到缓存
        redisTemplate.opsForValue().set("message",UUID.randomUUID().toString());
        //  解锁先不写，因为有自动解锁功能！
        return "写入 over!";
    }

    //    @Override
        //    public void testLock() {
        //        /*
        //        1.  获取缓存中的num 数据！
        //            true:   如果获取到了，则对这个数据进行+1 , 在写入缓存！
        //            false:  如果没有获取到，则直接返回
        //         */
        //        //  使用setnx 属于String 类型的命令 set lock v1
        //        //  Boolean flag = this.redisTemplate.opsForValue().setIfAbsent("lock", "v1");
        //        //  推荐使用：set key value ex/px timeOut nx/xx;  set 属于字符串类型
        //        //  Boolean flag = this.redisTemplate.opsForValue().setIfAbsent("lock", "v1", 3, TimeUnit.SECONDS);
        //        //  使用UUID 防止误删锁
        //        String uuid = UUID.randomUUID().toString();
        //        Boolean flag = this.redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3, TimeUnit.SECONDS);
        //        //  如果flag = true 则表示获取到了锁！
        //        if (flag){
        //            //  业务逻辑
        //            String numValue = redisTemplate.opsForValue().get("num");
        //            //  判断
        //            if (StringUtils.isEmpty(numValue)){
        //                return;
        //            }
        //            //  如果不是空，进行+1 操作！ 在写入缓存！
        //            int num = Integer.parseInt(numValue);
        //
        //
        //            //  写入缓存！ ++num  num++
        //            redisTemplate.opsForValue().set("num",String.valueOf(++num));
        //
        //            //  删除锁
        //            //            if (uuid.equals(redisTemplate.opsForValue().get("lock"))){
        //            //                //  相等则删除锁！ index1 比较通过！此时还没有执行删除呢。锁过期了，index2进来了。
        //            //                redisTemplate.delete("lock");
        //            //            }
        //            //  if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
        //            //  定义lua 脚本
        //            String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call ('del',KEYS[1]) else return 0 end";
        //
        //            //  RedisScript 这个是接口：
        //            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        //            //  将lua 脚本放入方法中
        //            redisScript.setScriptText(script);
        //            //  设置返回值类型
        //            redisScript.setResultType(Long.class);
        //
        //            //  使用lua 脚本
        //            //  第一个参数 RedisScript ，第二个参数 应该是key ,第三个参数：表示key 所对应的值
        //            redisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);
        //        }else{
        //            //  flag = flase
        //            //  等待睡眠
        //            try {
        //                Thread.sleep(100);
        //                //  自旋
        //                testLock();
        //            } catch (InterruptedException e) {
        //                e.printStackTrace();
        //            }
        //        }
        //    }
}
